package com.fc.remoting.message;

import java.nio.ByteBuffer;

import com.fc.remoting.exception.BodyTooLongException;
import com.fc.remoting.exception.HeaderCheckFailedException;

public class RemotingMessage {

	private RemotingHeader header;
	private byte[] body;

	/**
	 * 根据bytebuffer创建消息对象
	 * 
	 * @param byteBuffer
	 * @return
	 */
	public static RemotingMessage createMessage(ByteBuffer byteBuffer) {
		RemotingMessage result = new RemotingMessage();
		result.header = RemotingHeader.createHeader(byteBuffer);
		byte[] bytes = new byte[byteBuffer.capacity() - byteBuffer.position()];
		byteBuffer.get(bytes);
		result.body = bytes;

		// 校验
		byte check = (byte) result.header.getCheckCodePart();
		for(byte b:result.body){
			check = (byte) (check ^ b);
		}
		if (check != result.header.getCheckCode()) {
			throw new HeaderCheckFailedException("RemotingHeader check failed");
		}

		return result;
	}

	/**
	 * 创建消息对象
	 * 
	 * @param header
	 * @param body
	 * @return
	 */
	public static RemotingMessage createMessage(RemotingHeader header, byte[] body) {
		RemotingMessage result = new RemotingMessage();
		result.header = header;
		result.body = body;
		return result;
	}

	/**
	 * 创建一个默认消息头的消息
	 * 
	 * @param body
	 * @return
	 */
	public static RemotingMessage createMessageInDefaultHeader(byte[] body) {
		return createMessage(new RemotingHeader(), body);
	}

	/**
	 * 只打包Header，body部分独立传输
	 * 
	 * @param bodyLength
	 * @return
	 */
	private ByteBuffer encodeHeader(final short bodyLength) {
		// 1> total length size
		short length = 0;

		// 2> check code length
		length += 1;
		// 3> version length
		length += 1;
		// 4> message type length
		length += 1;
		// 5> module length
		// length += 1;
		// 6> order length
		// length += 1;
		// 7> encrypt type length
		length += 1;
		// 8> compress type length
		length += 1;

		length += bodyLength;

		ByteBuffer result = ByteBuffer.allocate(2 + length - bodyLength);
		// 9> length
		result.putShort(length);

		// 10> check code
		byte checkCode = header.getCheckCodePart();
		for (byte b : body) {
			checkCode = (byte) (checkCode ^ b);
		}
		result.put(checkCode);

		// 11> vsersion
		result.put(header.getVersion());

		// 12> message type
		result.put(header.getMsgType());

		// 13> module
		// result.put(header.getModule());

		// 14> order
		// result.put(header.getOrder());

		// 15> encrypt type
		result.put(header.getEncryptType());

		// 16 > Compress type
		result.put(header.getCompressType());

		return result;
	}

	/**
	 * 构建message
	 * 
	 * @return
	 */
	public ByteBuffer build() throws BodyTooLongException {
		if (this.body.length > Short.MAX_VALUE) {
			throw new BodyTooLongException("Body-length too long,Max is " + Short.MAX_VALUE);
		}
		ByteBuffer byteBuffer = encodeHeader((short) this.body.length);
		// byteBuffer.put(body);
		byteBuffer.flip();
		return byteBuffer;
	}

	public byte[] getBody() {
		return body;
	}

	public RemotingHeader getHeader() {
		return header;
	}

	public static void main(String[] args) {
		RemotingMessage message = DefaultRemotingMessage.connectMessage("abc", "abc", "abc");
		ByteBuffer buffer = message.build();
		System.out.println(buffer.getShort());
		System.out.println("checkcode:" + buffer.get());
		System.out.println("version:" + buffer.get());
		System.out.println("type:" + buffer.get());
		System.out.println("encrypt:" + buffer.get());
		System.out.println("compress:" + buffer.get());
		System.out.println(new String(message.getBody()));
	}
}
